"""
文件操作函数的集合
"""

import pandas
from py2neo import Graph, Node, NodeMatcher, RelationshipMatcher

from src.database.config import DataSet
from src.time_utils.transformer import TimeTransformer

from src.database.push import push_to_neo4j


# 判断是否是真正的数字
def is_number(s):
    try:
        float(s)
        return True
    except ValueError:
        return False

def update_to_neo4j(update_data, offset):
    graph = Graph("http://localhost:7474", auth=("neo4j", "123456"))
    matcher = NodeMatcher(graph)
    dataset = update_data['dataset']
    machine = update_data['machine']
    source = update_data['source']
    version = update_data['version']
    unique_name_start = dataset + "-" + machine + "-" + source + "-"
    d: DataSet = DataSet(dataset)
    d: DataSet = d.load_from_config()
    columns: dict = d.machines[machine].sources[source].columns
    column_names = columns.keys()

    query_result = matcher.match(dataset, machine, source)
    node_list = list(query_result)
    node_map = node_list2map(node_list)
    adddata = update_data['add']
    labeldata = update_data['label']

    Dataset = DataSet(dataset).load_from_config()

    tx = graph.begin()
    for key, value in adddata.items():

        if (not value['start'] != "") and (not value['end'] != "") and (
                not value['time'] != ""):
            # 可以抽取成新的函数
            unique_name_a = unique_name_start + str(value['start'])
            unique_name_b = unique_name_start + str(value['end'])
            if unique_name_a not in node_map.keys():
                node_a = create_new_node(str(value['start']), dataset, machine, source)
                tx.create(node_a)
                node_map[unique_name_a] = node_a

            if unique_name_b not in node_map.keys():
                node_b = create_new_node(str(value['end']), dataset, machine, source)
                tx.create(node_b)
                node_map[unique_name_b] = node_b

            node_a = node_map[unique_name_a]
            node_b = node_map[unique_name_b]
            relation = dict()

            ts = str(value['time'])
            relation['time'] = ts
            # 计算时间偏移量
            if not is_number(ts):
                ts = TimeTransformer.time2ts(ts)
            fixed_ts = float(ts) + offset
            relation['uni_time'] = str(fixed_ts)

            # relation = Relationship(node_a, str(df.index[i]), node_b)
            # relation['relation_type'] = str(df['relation_type'][i])
            for k, v in value.items():
                pre_value = v
                if k == 'time' or k == 'start' or k == 'end' or k == 'relation_type':
                    continue
                if columns[k].type == 'string' or str(pre_value) == "nan":
                    value_ = str(pre_value)
                elif columns[k].type == 'number':
                    value_ = float(pre_value)
                elif columns[k].type == 'int':
                    value_ = int(pre_value)
                elif columns[k].type == 'bool':
                    value_ = bool(pre_value)

                if (not hasattr(columns[k], 'annotation')) or columns[k].annotation == "edge":
                    relation[k] = value_
                elif columns[k].annotation == "start":
                    node_a[k] = value_
                else:
                    node_b[k] = value_

            # tx.create(relation)
            tx.push(node_a)
            # tx.push(node_b)
            create_edge(tx, unique_name_a, unique_name_b, str(value['relation_type']), dict2str(relation))

        elif (not value['start'] != "") and (value['end'] != "") and (
                not value['time'] != ""):
            unique_name_a = unique_name_start + str(value['start'])
            if unique_name_a not in node_map.keys():
                node_a = create_new_node(str(value['start']), dataset, machine, source)
                tx.create(node_a)
                node_map[unique_name_a] = node_a
            node_a = node_map[unique_name_a]
            # relation = Relationship(node_a, str(df.index[i]), node_a)
            relation = dict()

            ts = str(value['time'])
            relation['time'] = ts
            # 计算时间偏移量
            if not is_number(ts):
                ts = TimeTransformer.time2ts(ts)
            fixed_ts = float(ts) + offset
            relation['uni_time'] = str(fixed_ts)

            for k, v in value.items():
                pre_value = v
                if k == 'time' or k == 'start' or k == 'end' or k == 'relation_type':
                    continue
                if columns[k].type == 'string' or str(pre_value) == "nan":
                    value_ = str(pre_value)
                elif columns[k].type == 'number':
                    value_ = float(pre_value)
                elif columns[k].type == 'int':
                    value_ = int(pre_value)
                elif columns[k].type == 'bool':
                    value_ = bool(pre_value)

                if (not hasattr(columns[k], 'annotation')) or columns[k].annotation == "edge":
                    relation[k] = value_
                else:
                    node_a[k] = value_
            # tx.create(relation)
            tx.push(node_a)
            create_edge(tx, unique_name_a, unique_name_a, str('1'), dict2str(relation))  # 一元关系自环


        elif (not value['start'] == "") and (not value['end'] != "") and (
                value['time'] == ""):
            # time为空，但start和end非空

            unique_name_a = unique_name_start + str(value['start'])
            unique_name_b = unique_name_start + str(value['end'])
            if unique_name_a not in node_map.keys():
                node_a = create_new_node(str(value['start']), dataset, machine, source)
                tx.create(node_a)
                node_map[unique_name_a] = node_a

            if unique_name_b not in node_map.keys():
                node_b = create_new_node(str(value['end']), dataset, machine, source)
                tx.create(node_b)
                node_map[unique_name_b] = node_b

            node_a = node_map[unique_name_a]
            node_b = node_map[unique_name_b]

            relation = dict()

            relation['time'] = "NULL"
            # time为空则uni_time也为空
            relation['uni_time'] = "NULL"

            for k, v in value.items():
                pre_value = v
                if k == 'time' or k == 'start' or k == 'end' or k == 'relation_type':
                    continue

                if columns[k].type == 'string' or str(pre_value) == "nan":
                    value_ = str(pre_value)
                elif columns[k].type == 'number':
                    value_ = float(pre_value)
                elif columns[k].type == 'int':
                    value_ = int(pre_value)
                elif columns[k].type == 'bool':
                    value_ = bool(pre_value)

                if (not hasattr(columns[k], 'annotation')) or columns[k].annotation == "edge":
                    relation[k] = value_
                else:
                    node_a[k] = value_
            # tx.create(relation)
            tx.push(node_a)
            create_edge(tx, unique_name_a, unique_name_b, str(value['relation_type']), dict2str(relation))




        elif (value['start'] != "") and (value['end'] != "") and (
                value['time'] != ""):
            # time为空，start非空而end为空
            # 此时数据为一个节点的属性
            unique_name_a = unique_name_start + str(value['start'])

            if unique_name_a not in node_map.keys():
                node_a = create_new_node(str(value['start']), dataset, machine, source)
                tx.create(node_a)
                node_map[unique_name_a] = node_a

            node_a = node_map[unique_name_a]
            node_a['time'] = "NULL"
            node_a['uni_time'] = "NULL"  # 这种情况time为空

            for k, v in value.items():
                pre_value = v
                if k == 'time' or k == 'start' or k == 'end' or k == 'relation_type':
                    continue

                if columns[k].type == 'string' or str(pre_value) == "nan":
                    value_ = str(pre_value)
                elif columns[k].type == 'number':
                    value_ = float(pre_value)
                elif columns[k].type == 'int':
                    value_ = int(pre_value)
                elif columns[k].type == 'bool':
                    value_ = bool(pre_value)

                node_a[k] = value_
            # tx.create(relation)
            tx.push(node_a)

        elif (value['start'] != "") and (value['end'] != "") and (
                value['time'] != ""):
            # time为空，start空而end非空
            # 此时数据为一个节点的属性
            unique_name_a = unique_name_start + str(value['end'])

            if unique_name_a not in node_map.keys():
                node_a = create_new_node(str(value['end']), dataset, machine, source)
                tx.create(node_a)
                node_map[unique_name_a] = node_a

            node_a = node_map[unique_name_a]
            node_a['time'] = "NULL"
            node_a['uni_time'] = "NULL"
            for k, v in value.items():
                pre_value = v
                if k == 'time' or k == 'start' or k == 'end' or k == 'relation_type':
                    continue

                if columns[k].type == 'string' or str(pre_value) == "nan":
                    value_ = str(pre_value)
                elif columns[k].type == 'number':
                    value_ = float(pre_value)
                elif columns[k].type == 'int':
                    value_ = int(pre_value)
                elif columns[k].type == 'bool':
                    value_ = bool(pre_value)

                node_a[k] = value_
            # tx.create(relation)
            tx.push(node_a)

        elif (value['start'] != "") and (value['end'] != "") and (
                value['time'] != ""):
            # time为空，start空、end空
            # 无时间戳的额外信息作为孤立节点
            # 新创立一个特殊标签
            idx = gen_isolatednode_idx(node_map, "isolated_node_timeless") + 1
            unique_name_a = "isolated_node_timeless" + str(idx)

            node_a = create_new_node(unique_name_a, dataset, machine, source)
            tx.create(node_a)
            node_map[unique_name_a] = node_a
            node_a['time'] = "NULL"
            node_a['uni_time'] = "NULL"

            for k, v in value.items():
                pre_value = v
                if k == 'time' or k == 'start' or k == 'end' or k == 'relation_type':
                    continue

                if columns[k].type == 'string' or str(pre_value) == "nan":
                    value_ = str(pre_value)
                elif columns[k].type == 'number':
                    value_ = float(pre_value)
                elif columns[k].type == 'int':
                    value_ = int(pre_value)
                elif columns[k].type == 'bool':
                    value_ = bool(pre_value)

                node_a[k] = value_
            # tx.create(relation)
            tx.push(node_a)

        elif (pandas.isna(value['start'])) and (pandas.isna(value['end'])) and (
                not pandas.isna(value['time'])):
            # time非空，start空、end空
            # 有时间戳的额外信息作为孤立节点
            # 新创立一个特殊标签
            idx = gen_isolatednode_idx(node_map, "isolated_node_hastime") + 1
            unique_name_a = "isolated_node_hastime" + str(idx)

            node_a = create_new_node(unique_name_a, dataset, machine, source)
            tx.create(node_a)
            node_map[unique_name_a] = node_a

            ts = str(value['time'])
            node_a['time'] = ts
            # 计算时间偏移量
            if not is_number(ts):
                ts = TimeTransformer.time2ts(ts)
            fixed_ts = float(ts) + offset
            node_a['uni_time'] = str(fixed_ts)

            for k, v in value.items():
                pre_value = v
                if k == 'time' or k == 'start' or k == 'end' or k == 'relation_type':
                    continue

                if columns[k].type == 'string' or str(pre_value) == "nan":
                    value_ = str(pre_value)
                elif columns[k].type == 'number':
                    value_ = float(pre_value)
                elif columns[k].type == 'int':
                    value_ = int(pre_value)
                elif columns[k].type == 'bool':
                    value_ = bool(pre_value)

                node_a[k] = value_
            # tx.create(relation)
            tx.push(node_a)

        elif (pandas.isna(value['start'])) and (not pandas.isna(value['end'])) and (
                not pandas.isna(value['time'])):
            unique_name_a = unique_name_start + str(value['end'])
            if unique_name_a not in node_map.keys():
                node_a = create_new_node(str(value['end']), dataset, machine, source)
                tx.create(node_a)
                node_map[unique_name_a] = node_a
            node_a = node_map[unique_name_a]
            # relation = Relationship(node_a, str(df.index[i]), node_a)
            relation = dict()

            ts = str(value['time'])
            relation['time'] = ts
            # 计算时间偏移量
            if not is_number(ts):
                ts = TimeTransformer.time2ts(ts)
            fixed_ts = float(ts) + offset
            relation['uni_time'] = str(fixed_ts)

            for k, v in value.items():
                pre_value = v
                if k == 'time' or k == 'start' or k == 'end' or k == 'relation_type':
                    continue

                if columns[k].type == 'string' or str(pre_value) == "nan":
                    value_ = str(pre_value)
                elif columns[k].type == 'number':
                    value_ = float(pre_value)
                elif columns[k].type == 'int':
                    value_ = int(pre_value)
                elif columns[k].type == 'bool':
                    value_ = bool(pre_value)

                if (not hasattr(columns[k], 'annotation')) or columns[k].annotation == "edge":
                    relation[k] = value_
                else:
                    node_a[k] = value_
            # tx.create(relation)
            tx.push(node_a)
            create_edge(tx, unique_name_a, unique_name_a, str('1'), dict2str(relation))  # 一元关系自环

    graph.commit(tx)
    print("commit add finish")
    tx = graph.begin()
    # print(labeldata)

    for key, value in labeldata.items():
        if (not pandas.isna(value['start'])):
            unique_name_a = unique_name_start + value['start']

        if (not pandas.isna(value['end'])):
            unique_name_b = unique_name_start + value['end']

        if (unique_name_a != unique_name_start):
            nodes = matcher.match(dataset, machine, source, unique_name=unique_name_a)

        node = nodes.first()
        if (not node.has_label(version)):
            node.add_label(version)
            tx.push(node)

        if (unique_name_b != unique_name_start):
            nodes = matcher.match(dataset, machine, source, unique_name=unique_name_b)

        node = nodes.first()
        if (not node.has_label(version)):
            # print(version)
            node.add_label(version)
            tx.push(node)

    graph.commit(tx)
    print("commit label finish")


# edit private datasets
def private_crud(offset, add, delete_relation, delete_node, dataset=None, machine=None, source=None):
    graph = Graph("http://localhost:7474", auth=("neo4j", "123456"))
    matcher = NodeMatcher(graph)
    # todo:offset check
    print("handling")

    unique_name_start = dataset + "-" + machine + "-" + source + "-"
    d: DataSet = DataSet(dataset)
    d: DataSet = d.load_from_config()

    columns: dict = d.machines[machine].sources[source].columns
    column_names = columns.keys()

    query_result = matcher.match(dataset, machine, source)
    node_list = list(query_result)
    node_map = node_list2map(node_list)

    Dataset = DataSet(dataset).load_from_config()

    tx = graph.begin()

    if add != None:
        print("private add begin")
        cruddata = add
        for i in range(len(cruddata)):
            item = cruddata[i]

            if (not item['start'] == "") and (not item['end'] == "") and (
                    not item['time'] == ""):
                # 可以抽取成新的函数
                unique_name_a = unique_name_start + str(item['start'])
                unique_name_b = unique_name_start + str(item['end'])
                if unique_name_a not in node_map.keys():
                    node_a = create_new_node(str(item['start']), dataset, machine, source)
                    tx.create(node_a)
                    node_map[unique_name_a] = node_a

                if unique_name_b not in node_map.keys():
                    node_b = create_new_node(str(item['end']), dataset, machine, source)
                    tx.create(node_b)
                    node_map[unique_name_b] = node_b

                node_a = node_map[unique_name_a]
                node_b = node_map[unique_name_b]
                relation = dict()

                ts = str(item['time'])
                relation['time'] = ts
                # 计算时间偏移量
                if not is_number(ts):
                    ts = TimeTransformer.time2ts(ts)
                fixed_ts = float(ts) + offset
                relation['uni_time'] = str(fixed_ts)

                # relation = Relationship(node_a, str(df.index[i]), node_b)
                # relation['relation_type'] = str(df['relation_type'][i])
                for k, v in item.items():
                    pre_value = v
                    if k == 'time' or k == 'start' or k == 'end' or k == 'relation_type':
                        continue
                    if columns[k].type == 'string' or str(pre_value) == "nan":
                        value_ = str(pre_value)
                    elif columns[k].type == 'number':
                        value_ = float(pre_value)
                    elif columns[k].type == 'int':
                        value_ = int(pre_value)
                    elif columns[k].type == 'bool':
                        value_ = bool(pre_value)

                    if (not hasattr(columns[k], 'annotation')) or columns[k].annotation == "edge":
                        relation[k] = value_
                    elif columns[k].annotation == "start":
                        node_a[k] = value_
                    else:
                        node_b[k] = value_

                # tx.create(relation)
                tx.push(node_a)
                # tx.push(node_b)
                create_edge(tx, unique_name_a, unique_name_b, str(item['relation_type']), dict2str(relation))

            elif (not item['start'] == "") and (item['end'] == "") and (
                    not item['time'] == ""):
                unique_name_a = unique_name_start + str(item['start'])
                if unique_name_a not in node_map.keys():
                    node_a = create_new_node(str(item['start']), dataset, machine, source)
                    tx.create(node_a)
                    node_map[unique_name_a] = node_a
                node_a = node_map[unique_name_a]
                # relation = Relationship(node_a, str(df.index[i]), node_a)
                relation = dict()

                ts = str(item['time'])
                relation['time'] = ts
                # 计算时间偏移量
                if not is_number(ts):
                    ts = TimeTransformer.time2ts(ts)
                fixed_ts = float(ts) + offset
                relation['uni_time'] = str(fixed_ts)

                for k, v in item.items():
                    pre_value = v
                    if k == 'time' or k == 'start' or k == 'end' or k == 'relation_type':
                        continue
                    if columns[k].type == 'string' or str(pre_value) == "nan":
                        value_ = str(pre_value)
                    elif columns[k].type == 'number':
                        value_ = float(pre_value)
                    elif columns[k].type == 'int':
                        value_ = int(pre_value)
                    elif columns[k].type == 'bool':
                        value_ = bool(pre_value)

                    if (not hasattr(columns[k], 'annotation')) or columns[k].annotation == "edge":
                        relation[k] = value_
                    else:
                        node_a[k] = value_
                # tx.create(relation)
                tx.push(node_a)
                create_edge(tx, unique_name_a, unique_name_a, str('1'), dict2str(relation))  # 一元关系自环


            elif (not item['start'] == "") and (not item['end'] == "") and (
                    item['time'] == ""):
                # time为空，但start和end非空

                unique_name_a = unique_name_start + str(item['start'])
                unique_name_b = unique_name_start + str(item['end'])
                if unique_name_a not in node_map.keys():
                    node_a = create_new_node(str(item['start']), dataset, machine, source)
                    tx.create(node_a)
                    node_map[unique_name_a] = node_a

                if unique_name_b not in node_map.keys():
                    node_b = create_new_node(str(item['end']), dataset, machine, source)
                    tx.create(node_b)
                    node_map[unique_name_b] = node_b

                node_a = node_map[unique_name_a]
                node_b = node_map[unique_name_b]

                relation = dict()

                relation['time'] = "NULL"
                # time为空则uni_time也为空
                relation['uni_time'] = "NULL"

                for k, v in item.items():
                    pre_value = v
                    if k == 'time' or k == 'start' or k == 'end' or k == 'relation_type':
                        continue

                    if columns[k].type == 'string' or str(pre_value) == "nan":
                        value_ = str(pre_value)
                    elif columns[k].type == 'number':
                        value_ = float(pre_value)
                    elif columns[k].type == 'int':
                        value_ = int(pre_value)
                    elif columns[k].type == 'bool':
                        value_ = bool(pre_value)

                    if (not hasattr(columns[k], 'annotation')) or columns[k].annotation == "edge":
                        relation[k] = value_
                    else:
                        node_a[k] = value_
                # tx.create(relation)
                tx.push(node_a)
                create_edge(tx, unique_name_a, unique_name_b, str(item['relation_type']), dict2str(relation))




            elif (not item['start'] == "") and (item['end'] == "") and (
                    item['time'] == ""):
                # time为空，start非空而end为空
                # 此时数据为一个节点的属性
                unique_name_a = unique_name_start + str(item['start'])

                if unique_name_a not in node_map.keys():
                    node_a = create_new_node(str(item['start']), dataset, machine, source)
                    tx.create(node_a)
                    node_map[unique_name_a] = node_a

                node_a = node_map[unique_name_a]
                node_a['time'] = "NULL"
                node_a['uni_time'] = "NULL"  # 这种情况time为空

                for k, v in item.items():
                    pre_value = v
                    if k == 'time' or k == 'start' or k == 'end' or k == 'relation_type':
                        continue

                    if columns[k].type == 'string' or str(pre_value) == "nan":
                        value_ = str(pre_value)
                    elif columns[k].type == 'number':
                        value_ = float(pre_value)
                    elif columns[k].type == 'int':
                        value_ = int(pre_value)
                    elif columns[k].type == 'bool':
                        value_ = bool(pre_value)

                    node_a[k] = value_
                # tx.create(relation)
                tx.push(node_a)

            elif (item['start'] == "") and (not item['end'] == "") and (
                    item['time'] == ""):
                # time为空，start空而end非空
                # 此时数据为一个节点的属性
                unique_name_a = unique_name_start + str(item['end'])

                if unique_name_a not in node_map.keys():
                    node_a = create_new_node(str(item['end']), dataset, machine, source)
                    tx.create(node_a)
                    node_map[unique_name_a] = node_a

                node_a = node_map[unique_name_a]
                node_a['time'] = "NULL"
                node_a['uni_time'] = "NULL"
                for k, v in item.items():
                    pre_value = v
                    if k == 'time' or k == 'start' or k == 'end' or k == 'relation_type':
                        continue

                    if columns[k].type == 'string' or str(pre_value) == "nan":
                        value_ = str(pre_value)
                    elif columns[k].type == 'number':
                        value_ = float(pre_value)
                    elif columns[k].type == 'int':
                        value_ = int(pre_value)
                    elif columns[k].type == 'bool':
                        value_ = bool(pre_value)

                    node_a[k] = value_
                # tx.create(relation)
                tx.push(node_a)

            elif (item['start'] == "") and (item['end'] == "") and (
                    item['time'] == ""):
                # time为空，start空、end空
                # 无时间戳的额外信息作为孤立节点
                # 新创立一个特殊标签
                idx = gen_isolatednode_idx(node_map, "isolated_node_timeless") + 1
                unique_name_a = "isolated_node_timeless" + str(idx)

                node_a = create_new_node(unique_name_a, dataset, machine, source)
                tx.create(node_a)
                node_map[unique_name_a] = node_a
                node_a['time'] = "NULL"
                node_a['uni_time'] = "NULL"

                for k, v in item.items():
                    pre_value = v
                    if k == 'time' or k == 'start' or k == 'end' or k == 'relation_type':
                        continue

                    if columns[k].type == 'string' or str(pre_value) == "nan":
                        value_ = str(pre_value)
                    elif columns[k].type == 'number':
                        value_ = float(pre_value)
                    elif columns[k].type == 'int':
                        value_ = int(pre_value)
                    elif columns[k].type == 'bool':
                        value_ = bool(pre_value)

                    node_a[k] = value_
                # tx.create(relation)
                tx.push(node_a)

            elif (item['start'] == "") and (item['end'] == "") and (
                    not item['time'] == ""):
                # time非空，start空、end空
                # 有时间戳的额外信息作为孤立节点
                # 新创立一个特殊标签
                idx = gen_isolatednode_idx(node_map, "isolated_node_hastime") + 1
                unique_name_a = "isolated_node_hastime" + str(idx)

                node_a = create_new_node(unique_name_a, dataset, machine, source)
                tx.create(node_a)
                node_map[unique_name_a] = node_a

                ts = str(item['time'])
                node_a['time'] = ts
                # 计算时间偏移量
                if not is_number(ts):
                    ts = TimeTransformer.time2ts(ts)
                fixed_ts = float(ts) + offset
                node_a['uni_time'] = str(fixed_ts)

                for k, v in item.items():
                    pre_value = v
                    if k == 'time' or k == 'start' or k == 'end' or k == 'relation_type':
                        continue

                    if columns[k].type == 'string' or str(pre_value) == "nan":
                        value_ = str(pre_value)
                    elif columns[k].type == 'number':
                        value_ = float(pre_value)
                    elif columns[k].type == 'int':
                        value_ = int(pre_value)
                    elif columns[k].type == 'bool':
                        value_ = bool(pre_value)

                    node_a[k] = value_
                # tx.create(relation)
                tx.push(node_a)

            elif (item['start'] == "") and (not item['end'] == "") and (
                    not item['time'] == ""):
                unique_name_a = unique_name_start + str(item['end'])
                if unique_name_a not in node_map.keys():
                    node_a = create_new_node(str(item['end']), dataset, machine, source)
                    tx.create(node_a)
                    node_map[unique_name_a] = node_a
                node_a = node_map[unique_name_a]
                # relation = Relationship(node_a, str(df.index[i]), node_a)
                relation = dict()

                ts = str(item['time'])
                relation['time'] = ts
                # 计算时间偏移量
                if not is_number(ts):
                    ts = TimeTransformer.time2ts(ts)
                fixed_ts = float(ts) + offset
                relation['uni_time'] = str(fixed_ts)

                for k, v in item.items():
                    pre_value = v
                    if k == 'time' or k == 'start' or k == 'end' or k == 'relation_type':
                        continue

                    if columns[k].type == 'string' or str(pre_value) == "nan":
                        value_ = str(pre_value)
                    elif columns[k].type == 'number':
                        value_ = float(pre_value)
                    elif columns[k].type == 'int':
                        value_ = int(pre_value)
                    elif columns[k].type == 'bool':
                        value_ = bool(pre_value)

                    if (not hasattr(columns[k], 'annotation')) or columns[k].annotation == "edge":
                        relation[k] = value_
                    else:
                        node_a[k] = value_
                # tx.create(relation)
                tx.push(node_a)
                create_edge(tx, unique_name_a, unique_name_a, str('1'), dict2str(relation))  # 一元关系自环

        print("commit add finish")
    graph.commit(tx)
    tx = graph.begin()
    if delete_relation != None:
        cruddata = delete_relation
        print("private delete relation begin")
        for i in range(len(cruddata)):
            item = cruddata[i]
            unique_name_1 = unique_name_start + item['start']
            unique_name_2 = unique_name_start + item['end']
            relation_type = item['relation_type']
            # print(relation_type)
            print(unique_name_1)
            list(matcher.match(dataset, machine, source, ))
            node1 = list(matcher.match(dataset, machine, source, unique_name=unique_name_1))[0]
            node2 = list(matcher.match(dataset, machine, source, unique_name=unique_name_2))[0]

            properties = dict()
            for k, v in item.items():
                pre_value = v
                if k == 'start' or k == 'end' or k == 'relation_type' or k == 'time':
                    continue
                if columns[k].type == 'string' or str(pre_value) == "nan":
                    value_ = str(pre_value)
                elif columns[k].type == 'number':
                    value_ = float(pre_value)
                elif columns[k].type == 'int':
                    value_ = int(pre_value)
                elif columns[k].type == 'bool':
                    value_ = bool(pre_value)

                if (not hasattr(columns[k], 'annotation')) or columns[k].annotation == "edge":
                    properties[k] = value_

            # relationship1 = Relationship(node1,"new",node2,**properties)
            # graph.create(relationship1)
            # ,**properties
            rmatcher = RelationshipMatcher(graph)
            print(list(rmatcher))
            for r in rmatcher.match(nodes=(node1, node2), r_type=relation_type, **properties):
                tx.separate(r)
            # graph.separate(relationship1)

            print("delete private relation end")

    if delete_node != None:
        cruddata = delete_node
        print("private delete node begin")
        for i in range(len(cruddata)):
            item = cruddata[i]
            unique_name_a = item['name']

            unique_name_a = unique_name_start + item['name']

            delete_private_node(tx, dataset, machine, source, unique_name_a)
        print("private delete node end")
    graph.commit(tx)


# 深拷贝
# 参数：原来的数据集名称、主机名称、数据源名称，新增的数据集名称、主机名称、数据源名称
def deep_copy_neo4j(pre_dataset, pre_machine, pre_source, cur_dataset, cur_machine, cur_source):
    unique_name_start = cur_dataset + "-" + cur_machine + "-" + cur_source + "-"
    graph = Graph("http://localhost:7474", auth=("neo4j", "123456"))
    tx = graph.begin()
    node_matcher = NodeMatcher(graph)
    relationship_matcher = RelationshipMatcher(graph)
    node_list = list(node_matcher.match(pre_dataset, pre_machine, pre_source))
    new_node_list = []
    # 处理Node
    for node in node_list:
        new_node = Node()
        new_node.add_label(cur_dataset)
        new_node.add_label(cur_machine)
        new_node.add_label(cur_source)
        for key in node:
            new_node[key] = node[key]
        new_node['unique_name'] = unique_name_start + new_node['name']
        new_node_list.append(new_node)
        tx.create(new_node)
        tx.push(new_node)

    graph.commit(tx)
    tx = graph.begin()

    # 处理Relationship
    # FIXME:此处暴力循环，效率可能较低，之后优化
    for i, node1 in enumerate(node_list):
        for j, node2 in enumerate(node_list):
            relationship_list = list(relationship_matcher.match((node1, node2)))
            for relationship in relationship_list:
                relation = dict()
                for key in relationship:
                    relation[key] = relationship[key]
                create_edge(tx, new_node_list[i]['unique_name'], new_node_list[j]['unique_name'],
                            get_rtype(relationship), dict2str(relation))
    graph.commit(tx)

    # # 验证
    # old_node_list = list(node_matcher.match(pre_dataset, pre_machine, pre_source))
    # print('old_node_list :')
    # for node in old_node_list:
    #     print(node)
    # new_node_list = list(node_matcher.match(cur_dataset, cur_machine, cur_source))
    # print('new_node_list :')
    # for node in new_node_list:
    #     print(node)
    # print('old_relationship_list :')
    # for node1 in old_node_list:
    #     for node2 in old_node_list:
    #         relationship_list = list(relationship_matcher.match((node1, node2)))
    #         for relationship in relationship_list:
    #             print(relationship)
    # print('new_relationship_list :')
    # for node1 in new_node_list:
    #     for node2 in new_node_list:
    #         relationship_list = list(relationship_matcher.match((node1, node2)))
    #         for relationship in relationship_list:
    #             print(relationship)


def create_new_node(node_name, dataset: str, machine: str, source: str):
    print(node_name, "does not exist, it will be created.")
    unique_name_start = dataset + "-" + machine + "-" + source + "-"
    node_a = Node(name=node_name)
    node_a.add_label(dataset)
    node_a.add_label(machine)
    node_a.add_label(source)
    node_a['unique_name'] = unique_name_start + str(node_name)
    return node_a


def check_node_exists(node_list, unique_name):
    # 检查元素是否存在，若存在，返回该元素；若不存在，返回空值
    nodes = list(node_list.where("_.unique_name = '" + unique_name + "'"))
    if len(nodes) > 0:
        return nodes[0]
    else:
        return None


def delete_private_node(tx, dataset, machine, source, unique_name):
    # 删除指定unique_name的节点以及相关联的关系
    tx.run(
        "match (n) where any(label in labels(n) WHERE label in [\'{}\', \'{}\',\'{}\']) AND n.unique_name=\'{}\' DETACH DELETE n".format(
            dataset, machine, source, unique_name))


def gen_isolatednode_idx(node_map, name):
    cnt = 0

    for key in node_map:
        print(key)
        if name in key:
            cnt = cnt + 1

    return cnt


def node_list2map(node_list) -> dict:
    node_map = {}
    for node in node_list:
        node_map[node['unique_name']] = node
    return node_map


def create_edge(tx, unique_name_a, unique_name_b, relation_type, params):
    # 考虑关系名称可能包含特殊字符，使用反引号`
    tx.run(
        "MATCH (a),(b) where a.unique_name=$p AND b.unique_name=$q CREATE (a)-[r:`{}`{}]->(b)".format(
            str(relation_type),
            str(params)),
        p=unique_name_a, q=unique_name_b)


def dict2str(params):
    # 需要对反斜杠\转义，考虑Windows下的路径
    # 避免单引号带来的麻烦，使用双引号，因此需要对双引号转义
    return '{' + ', '.join(
        [str(k) + ": " + (str(v) if type(v) == int or type(v) == float else '{}'.format(repr(str(v)))) for k, v in
         params.items()]) + '}'


def get_rtype(relationship):
    # 返回关系的类型
    return str(relationship).split(':')[1].split(' ')[0]


if __name__ == "__main__":
    push_to_neo4j("../../data/datasetname/machinename/sourcename/version.tsv", "datasetname", "machinename",
                  "sourcename")
    # print(dict2str({
    #     'Image_Path': r'C:\Windows\Explorer.EXE'
    # }))
